package pl.hucal.wmkassist.network;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;

import pl.hucal.wmkassist.activities.LoggingableActivity;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import com.facebook.android.AsyncFacebookRunner;
import com.facebook.android.AsyncFacebookRunner.RequestListener;
import com.facebook.android.DialogError;
import com.facebook.android.Facebook;
import com.facebook.android.FacebookError;
import com.facebook.android.Facebook.DialogListener;

/**
 * Facebook connector
 * 
 * Manages connection and logging in/out with user Facebook account. Only one
 * instance of the class is permited.
 * 
 * @author Tadeusz Hucal <tadeusz.hucal@gmail.com>
 */
public class FacebookConnector
{
    /** Tag for LogCat */
    private static final String TAG = "WMK_FacebookConnector";
    /** Facebook API object */
    Facebook facebook;
    /** Application ID for Facebook API */
    static final String APPLICATION_ID = "191492757631800";
    /** Class instance */
    static FacebookConnector instance = null;

    /**
     * Constructor
     */
    private FacebookConnector()
    {
        facebook = new Facebook(APPLICATION_ID);
    }

    /**
     * Get (and create if needed) class instance
     * 
     * @return
     */
    static synchronized public FacebookConnector getInstance()
    {
        if (instance == null)
        {
            instance = new FacebookConnector();
        }
        return instance;
    }

    /**
     * Set Facebook connection data
     * 
     * Allows to set data from session started in a different way or time
     * 
     * @param token
     *            OAuth access token
     * @param expires
     *            when the session expires
     */
    public void setSessionData(final String token, final long expires)
    {
        Log.d(TAG, "Loading session data: [Token: " + token + "] [Expires: " + expires + "]");
        if (token != null)
        {
            facebook.setAccessToken(token);
        }
        if (expires != 0)
        {
            facebook.setAccessExpires(expires);
        }
    }

    /**
     * Is logged?
     * 
     * Tells whether user has already sucessfully logged in with Facebook
     * 
     * @return
     */
    public boolean isLogged()
    {
        return facebook.isSessionValid();
    }

    /**
     * Connect and log in
     * 
     * Authorizes user with his/her Facebook account (only if not already logged
     * in)
     * 
     * @param loggingActivity
     *            activity in which logging-in should be started
     */
    public void connect(final Activity loggingActivity)
    {
        final LoggingableActivity loggingableActivity;
        if (loggingActivity instanceof LoggingableActivity)
        {
            loggingableActivity = (LoggingableActivity) loggingActivity;
        } else
        {
            throw new IllegalArgumentException("Given host activity must implement LoggingableActivity interface");
        }
        // Connect only if needed
        if (isLogged())
        {
            return;
        }
        facebook.authorize(loggingActivity, new String[] { "user_about_me" }, new DialogListener()
        {
            @Override
            public void onComplete(Bundle values)
            {
                Log.d(TAG, "Loggin with facebook successful.");
            }

            @Override
            public void onFacebookError(FacebookError error)
            {
                Log.e(TAG, "Facebook loggin-in error [type: " + error.getErrorType() + "]: [" + error.getErrorCode()
                        + "]" + error.getLocalizedMessage());
                FacebookConnector.this.resetSessionData();
                loggingableActivity.onLoggingError(error.getLocalizedMessage());
            }

            @Override
            public void onError(DialogError error)
            {
                Log.e(TAG, "Facebook logging-in dialog error: " + error.getLocalizedMessage());
                FacebookConnector.this.resetSessionData();
                loggingableActivity.onLoggingError(error.getLocalizedMessage());
            }

            @Override
            public void onCancel()
            {
                Log.d(TAG, "Logging into Facebook cancelled");
            }
        });
    }

    /**
     * Callback by Facebook API
     * 
     * @param requestCode
     * @param resultCode
     * @param data
     */
    public void authorizeCallback(final int requestCode, final int resultCode, final Intent data)
    {
        facebook.authorizeCallback(requestCode, resultCode, data);
    }

    /**
     * Get OAuth access token
     * 
     * @return
     */
    public String getAccessToken()
    {
        return facebook.getAccessToken();
    }

    /**
     * Get session expiration time
     * 
     * @return
     */
    public long getSessionExpires()
    {
        return facebook.getAccessExpires();
    }

    /**
     * Logout from Facebook
     * 
     * @param context
     *            the Android context in which the logout should be called
     */
    public void logout(final Context context)
    {
        logout(context, null);
    }

    /**
     * Logout from Facebook
     * 
     * @param context
     *            the Android context in which the logout should be called
     * @param dialog
     *            dialog related with logging out progress (usually blocking
     *            progress dialog)
     */
    public void logout(final Context context, final Dialog dialog)
    {
        AsyncFacebookRunner asyncRunner = new AsyncFacebookRunner(facebook);
        asyncRunner.logout(context, new RequestListener()
        {
            @Override
            public void onComplete(String response, Object state)
            {
                if (dialog != null)
                {
                    dialog.dismiss();
                }
                Log.d(TAG, "Logged out");
            }

            @Override
            public void onIOException(IOException e, Object state)
            {
                // FIXME
                if (dialog != null)
                {
                    dialog.dismiss();
                }
                Log.d(TAG, "IOexcept");
            }

            @Override
            public void onFileNotFoundException(FileNotFoundException e, Object state)
            {
                // FIXME
                if (dialog != null)
                {
                    dialog.dismiss();
                }
                Log.d(TAG, "onFileNotFoundException");
            }

            @Override
            public void onMalformedURLException(MalformedURLException e, Object state)
            {
                // FIXME
                if (dialog != null)
                {
                    dialog.dismiss();
                }
                Log.d(TAG, "onMalformedURLException");
            }

            @Override
            public void onFacebookError(FacebookError e, Object state)
            {
                // FIXME
                if (dialog != null)
                {
                    dialog.dismiss();
                }
                Log.d(TAG, "onFacebookError");
            }
        });
    }

    /**
     * Clear token and expires date
     */
    private void resetSessionData()
    {
        facebook.setAccessExpires(0);
        facebook.setAccessToken(null);
    }
}
